//
//  TSNetTools.m
//  TaShuo
//
//  Created by N-X on 2018/1/17.
//  Copyright © 2018年 MRNAN. All rights reserved.
//

#import "TSNetTools.h"
#import <PPNetworkHelper.h>
#import "UIViewController+Utils.h"
#import <objc/runtime.h>
#import <SVProgressHUD.h>

static char groupErrorKey;
static char queueGroupKey;



@implementation TSNetTools
SINGLETON_IMPLEMENT_ARC(TSNetTools)

#pragma mark - Until

- (void)showHud
{
    [MBProgressHUD showHUDAddedTo:[UIViewController currentViewController].view animated:YES];
}

- (void)dissmissHud
{
    [MBProgressHUD hideHUDForView:[UIViewController currentViewController].view animated:YES];
}

#pragma mark - GET
//  不带缓存的
/** 在PPNetworkHelper基础上再包一层，做一些自定义的扩展。因为 PPNetworkHelper是依赖于cocoapods的，所以修改里面东西还是会被改变*/
- (NSURLSessionTask *)GET:(NSString *)URL
                   params:(id)params
           isShowProgress:(BOOL)isShowProgress
               completion:(NetCompletionHandle)completion
{
    
    if (![PPNetworkHelper isNetwork]) {
        NSError * error = [NSError errorWithDomain:@"" code:TSNetToolsErrorType_netNotConnect userInfo:@{NSLocalizedDescriptionKey:@"网络链接断开"}];
        [self handleError:error];
        completion(error,nil,NO);
        return nil;
    }
    NSURLSessionTask * task = [PPNetworkHelper GET:URL parameters:params success:^(id responseObject) {
        completion(nil,responseObject,NO);
    } failure:^(NSError * error) {
        [self handleError:error];
        completion(error,nil,NO);
    }];
    return task;
}

// 带缓存的
- (NSURLSessionTask *)Cache_GET:(NSString *)URL
                         params:(id)params
                 isShowProgress:(BOOL)isShowProgress
                     completion:(NetCompletionHandle)completion
{
    if (![PPNetworkHelper isNetwork]) {
        NSError * error = [NSError errorWithDomain:@"" code:TSNetToolsErrorType_netNotConnect userInfo:@{NSLocalizedDescriptionKey:@"网络链接断开"}];
        [self handleError:error];
        completion(error,nil,NO);
        return nil;
    }
    NSURLSessionTask * task = [PPNetworkHelper GET:URL parameters:params responseCache:^(id responseCache) {
        completion(nil,responseCache,YES);
    } success:^(id responseObject) {
        completion(nil,responseObject,NO);
    } failure:^(NSError * error) {
        [self handleError:error];
        completion(error,nil,NO);
    }];
    return task;
}

#pragma mark - POST
// POST 不带缓存的
- (NSURLSessionTask *)POST:(NSString *)URL
                    params:(id)params
            isShowProgress:(BOOL)isShowProgress
                completion:(NetCompletionHandle)completion
{
    if (![PPNetworkHelper isNetwork]) {
        NSError * error = [NSError errorWithDomain:@"" code:TSNetToolsErrorType_netNotConnect userInfo:@{NSLocalizedDescriptionKey:@"网络链接断开"}];
        [self handleError:error];
        completion(error,nil,NO);
        return nil;
    }
    if (isShowProgress) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self dissmissHud];
            [self showHud];
        });
    }

    kWeakSelf(self)
    NSURLSessionTask * task = [PPNetworkHelper POST:URL parameters:params success:^(id responseObject) {
        if (isShowProgress) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakself dissmissHud];
            });
        }
        completion(nil,responseObject,NO);
    } failure:^(NSError *error) {
        if (isShowProgress) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakself dissmissHud];
            });
        }
        [self handleError:error];
        completion(error,nil,NO);
    }];
    return task;
}

// 带缓存的
- (NSURLSessionTask *)Cache_POST:(NSString *)URL
                          params:(id)params
                  isShowProgress:(BOOL)isShowProgress
                      completion:(NetCompletionHandle)completion
{
    if (![PPNetworkHelper isNetwork]) {
        NSError * error = [NSError errorWithDomain:@"" code:TSNetToolsErrorType_netNotConnect userInfo:@{NSLocalizedDescriptionKey:@"网络链接断开"}];
        [self handleError:error];
        completion(error,nil,NO);
        return nil;
    }
    NSURLSessionTask * task = [PPNetworkHelper POST:URL parameters:params responseCache:^(id responseCache) {
        completion(nil,responseCache,YES);
    } success:^(id responseObject) {
        completion(nil,responseObject,NO);
    } failure:^(NSError * error) {
        [self handleError:error];
        completion(error,nil,NO);
    }];
    return task;
}

// 多组并发请求 post(不带缓存)
- (void)groupPost:(BlockAction)requests
          success:(BlockAction)success
          failure:(GroupResponseFailure)failure
{
    if (!requests) {
        return;
    }
    if (![PPNetworkHelper isNetwork]) {
        NSError * error = [NSError errorWithDomain:@"" code:TSNetToolsErrorType_netNotConnect userInfo:@{NSLocalizedDescriptionKey:@"网络链接断开"}];
        [self handleError:error];
        failure(@[error]);
        return ;
    }
    dispatch_group_t group = dispatch_group_create();
    objc_setAssociatedObject(group, &groupErrorKey, [NSMutableArray array], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    Method originMethod = class_getInstanceMethod(self.class, @selector(POST:params:isShowProgress:completion:));
    Method groupMethod = class_getInstanceMethod(self.class, @selector(sendePostRequestInGroup:params:isShowProgress:completion:));
    NSOperationQueue * queue = [[NSOperationQueue alloc]init];
    objc_setAssociatedObject(queue, &queueGroupKey, group, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    queue.qualityOfService = NSQualityOfServiceUserInitiated; // 次高优先级，用于用户需要马上执行的事件
    queue.maxConcurrentOperationCount = 3;
    [queue addOperationWithBlock:^{
        method_exchangeImplementations(originMethod, groupMethod);
        // 执行block
        requests();
        // 发出请求后就可以替换回original method，不必等待回调，尽量减小替换的时间窗口
        method_exchangeImplementations(originMethod, groupMethod);
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSMutableArray *arrayM = objc_getAssociatedObject(group, &groupErrorKey);
            if (arrayM.count > 0) {
                if (failure) {
                    failure(arrayM.copy);
                }
            } else if (success) {
                success();
            }
            
        });
    }];
}

- (void)sendePostRequestInGroup:(NSString *)urlStr
                         params:(id)params
                 isShowProgress:(BOOL)isShowProgress
                     completion:(NetCompletionHandle)completion
{
    dispatch_group_t group = objc_getAssociatedObject([NSOperationQueue currentQueue], &queueGroupKey);
    if (!group) {
        //说明是普通的单个请求，发起原来默认的请求（这个方法是在发起组请求的时候才会被调用的，所以已经是被换过的方法，这里应该调用切换过的那个方法）
        [self sendePostRequestInGroup:urlStr params:params isShowProgress:isShowProgress completion:completion];
        return;
    }
    
    dispatch_group_enter(group);
    // 执行original method
    [self sendePostRequestInGroup:urlStr params:params isShowProgress:isShowProgress completion:^(NSError *error, id responseJson, BOOL isCache) {
        if (!error) {
            completion ? completion(nil,responseJson,isCache):nil;
            if (!isCache) {
                dispatch_group_leave(group);
            }
        }else
        {
            completion?completion(error,nil,isCache):nil;
            NSMutableArray *arrayM = objc_getAssociatedObject(group, &groupErrorKey);
            [arrayM addObject:error];
            dispatch_group_leave(group);
        }
    }];
}

- (void)handleError:(NSError *)error
{
    // 判断错误原因，主要是： 超时，取消，网络错误
    NSString *errMsg = error.localizedDescription;
    
    switch (error.code) {
        case NSURLErrorCancelled:
            errMsg = nil;
            break;
            
        case NSURLErrorCannotFindHost:
            errMsg = @"十有八九断网啦，赶紧去设置看下吧！";
            break;
            
        case NSURLErrorTimedOut://请求超时
            errMsg = @"服务器被外星人搬走了o(╯□╰)o";
            break;
        case TSNetToolsErrorType_netNotConnect:
            errMsg = @"网络连接断开";
            break;
        default:
            errMsg = @"网络出错";
            break;
    }
    if (errMsg) {
//        [MBProgressHUD showErrorWithStatue:errMsg inView:[UIViewController currentViewController].view];
        [SVProgressHUD setDefaultStyle:SVProgressHUDStyleDark];
        [SVProgressHUD showErrorWithStatus:errMsg];
    }
}

@end
